package services.intermediate

import jdk.internal.org.jline.reader.History
import models.baseinfo.GYItemCodeRepository
import models.outstock.{OutStockRecive, OutStockRevRepository}
import play.api.Logging
import play.api.libs.json.{JsArray, JsObject, JsValue, Json}
import security.Checked
import services.OutStockPostParameters
import services.gyerpapi.GYCErpPost
import services.kingdee.{KingdeeConfig, KingdeePostV1}

import java.sql.Timestamp
import java.time.{LocalDate, LocalDateTime}
import java.time.format.DateTimeFormatter
import javax.inject.Inject
import scala.collection.mutable
import scala.collection.mutable.ListBuffer
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, ExecutionContext}

class GetDataFromGy @Inject()(
                               itemCodeRepo: GYItemCodeRepository,
                               osrRep: OutStockRevRepository,
                               kdPost: KingdeePostV1,
                               gyPost: GYCErpPost
                             )(implicit exec: ExecutionContext)
  extends Logging {

  private val dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")

  private def asString(v: JsValue) = v.asOpt[String].getOrElse(v.toString)

  private def updateGyItemCode(gyItemId: Long,
                               gyCode: String,
                               gyBarcode: String,
                               gyName: String,
                               status: Boolean = false) = {
    itemCodeRepo.update(gyItemId = gyItemId, gyCode = gyCode, gyName = gyName, gyBarcode = gyBarcode, status = status)
  }

  // 管易商品代码
  private def getGyItemCode() = {
    val limit = 100
    var page = 1
    var total = 1
    val lst: mutable.ArrayBuffer[(Long, String, String, Boolean)] = mutable.ArrayBuffer()
    val date = LocalDate.now()
    val start_date = date.plusDays(-30).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " 00:00:00"
    val end_date = date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " 00:00:00"
    while (page <= total) {
      val para_list = Json.obj(
        "method" -> "gy.erp.items.get",
        "page_no" -> page,
        "page_size" -> limit,
        "start_date" -> start_date,
        "end_date" -> end_date
      )
      val res = Await.result(gyPost.post(para_list), Duration.Inf)
      if ((res \ "success").as[Boolean]) {
        val a = (res \ "total").as[Int] / limit + 1
        if (a > total) total = a
        val arr = (res \ "items").as[Array[JsObject]].map { r =>
          (
            Checked.asString(r("id")).toLong,
            r("code").as[String],
            r("name").as[String],
            r("del").as[Boolean]
          )
        }
        for (f <- arr) {
          lst.append(f)
        }
      } else {
        logger.debug(res.toString())
        page = total + 1
      }
      logger.debug(s"total=$total,page=$page")
      page += 1
    }
    lst.map(r => updateGyItemCode(gyItemId = r._1, gyCode = r._2, gyName = r._3, status = r._4, gyBarcode = ""))
    lst
  }

  // 管易商品条码
  private def getGyBarCode() = {
    val limit = 100
    var page = 1
    var total = 1
    val lst: mutable.ArrayBuffer[(Long, String, String, String, Boolean)] = mutable.ArrayBuffer()
    val date = LocalDate.now()
    val start_date = date.plusDays(-30).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " 00:00:00"
    val end_date = date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " 00:00:00"
    while (page <= total) {
      val para_list = Json.obj(
        "method" -> "gy.erp.item.barcode.get",
        "page_no" -> page,
        "page_size" -> limit,
        "start_date" -> start_date,
        "end_date" -> end_date,
        "date_type" -> 1
      )
      val res = Await.result(gyPost.post(para_list), Duration.Inf)
      if ((res \ "success").as[Boolean]) {
        val a = (res \ "total").as[Int] / limit + 1
        if (a > total) total = a
        val arr = (res \ "barcode").as[Array[JsObject]].map { r =>
          (
            Checked.asString(r("item_id")).toLong,
            r("item_code").as[String],
            r("item_name").as[String],
            r("barcode").as[String],
            r("is_del").as[Boolean]
          )
        }
        for (f <- arr) {
          lst.append(f)
        }
      } else {
        logger.debug(res.toString())
        page = total + 1
      }
      logger.debug(s"total=$total,page=$page")
      page += 1
    }
    lst.map(r => updateGyItemCode(gyItemId = r._1, gyCode = r._2, gyName = r._3, status = !r._5, gyBarcode = r._4))
    lst
  }

  private def save2OSR(argJson: JsValue) = {
    val tr = argJson
    try {
      val code = (tr \ "code").as[String]
      val code_id = code.replaceAll("[^0-9]", "")
      val shop_code = (tr \ "shop_code").as[String]
      val wh_code = (tr \ "warehouse_code").as[String]
      val fEntity = Json.obj(
        "FEntity" ->
          Json.toJson(
            tr("details").as[Array[JsValue]].map(
              v => Json.obj(
                "FAllAmount" -> this.asString(v("amount_after")).toDouble,
                "FAmount" -> this.asString(v("amount")).toDouble,
                "FDiscount" -> this.asString(v("discount_fee")).toDouble,
                "FFeeAmount" -> this.asString(v("other_service_fee")).toDouble,
                "FGYEntryID" -> scala.util.Random.nextLong(1_000_000_000).toString,
                "FIsFree" -> (if (v("is_gift").as[Int] == 1) true else false),
                "FMaterialNumber" -> v("item_code").as[String],
                "FORDERBILLNO" -> v("platform_code").as[String],
                "FPrice" -> this.asString(v("price")).toDouble,
                "FQty" -> this.asString(v("qty")).toDouble.toInt,
                "FServiceAmount" -> this.asString(v("post_fee")).toDouble
              )
            )
          )
      )

      val req = OutStockRecive(
        //osrFEntity = true,
        osrFDate = Timestamp.valueOf(LocalDateTime.parse(tr("delivery_statusInfo")("delivery_date").as[String], dateFormat)),
        osrFGYBillNo = code, //"SDO"+ nowTime.getMillis,
        osrFShopNumber = shop_code, //"SHOP00101",
        osrFStockNumber = wh_code, //"ST0002",
        osrFEntityInfo = Option(fEntity.toString) //Option(new javax.sql.rowset.serial.SerialClob("""{"sssssss"}""".toCharArray))
      )
      osrRep.insertOSR(req)
      //      logger.debug(req.toString)
    } catch {
      case exception: Exception => logger.debug("save2OSR json error", exception)
    }
  }

  private def getDeliveryAtDays(start_date: String, end_date: String, history: Boolean = false) = {
    val limit = 10
    var page = 1
    var total = 1
    val lst: mutable.ArrayBuffer[JsValue] = mutable.ArrayBuffer()
    while (page <= total) {
      val para_list = if (history) {
        Json.obj(
          "method" -> "gy.erp.trade.deliverys.history.get",
          "page_no" -> page,
          "page_size" -> limit,
          "start_delivery_date" -> start_date,
          "end_delivery_date" -> end_date,
        )
      } else {
        Json.obj(
          "method" -> "gy.erp.trade.deliverys.get",
          "page_no" -> page,
          "page_size" -> limit,
          "start_delivery_date" -> start_date,
          "end_delivery_date" -> end_date,
          "delivery" -> 1
        )
      }
      val res = Await.result(gyPost.post(para_list), Duration.Inf)
      try {
        if ((res \ "success").asOpt[Boolean].getOrElse(false)) {
          val a = (res \ "total").as[Int] / limit + 1
          if (a > total) total = a
          val arr = (res \ "deliverys").as[Array[JsValue]]
          for (f <- arr) {
            lst.append(f)
            this.save2OSR(f)
          }
        } else {
          logger.debug(res.toString())
          page = total + 1
        }
        logger.debug(s"total=$total,page=$page")
        page += 1
      } catch {
        case exception: Exception => logger.debug("getDelivery -> exception:\n", exception)
      }
    }
    lst.map(r => this.save2OSR(r))
    lst.toString()
  }

  private def saveTradeReturns2Kd(argJson: JsValue) = {
    try {
      val tr = argJson
      val code = (tr \ "code").as[String]
      val code_id = code.replaceAll("[^0-9]", "")
      val shop_code = (tr \ "shop_code").as[String]
      val wh_code = (tr \ "warehousein_code").as[String]
      val date = (tr \ "receive_date").as[String]
      val para_fe = (tr \ "details").as[JsArray].value.map(v =>
        Json.obj(
          "FAllAmount" -> None,
          "FAmount" -> this.asString(v("amount_after")).toDouble,
          "FDiscount" -> this.asString(v("discount_fee")).toDouble,
          "FEOwnerNumber" -> None,
          "FEOwnerTypeId" -> None,
          "FExpiryDate" -> "1971-01-01 00:00:00",
          "FFeeAmount" -> this.asString(v("other_service_fee")).toDouble,
          //  "FServiceAmount" -> v("post_fee").as[Double],
          "FGYEntryID" -> scala.util.Random.nextLong(1_000_000_000).toString,
          "FLotNumber" -> 2018,
          "FMaterialNumber" -> (v \ "item_code").as[String],
          "FORDERBILLNO" -> "",
          "FORDERENTRYID" -> None,
          "FPrice" -> this.asString(v("price")).toDouble,
          "FProduceDate" -> "1971-01-01 00:00:00",
          "FQty" -> this.asString(v("real_in")).toDouble,
          "FSKUNumber" -> (v \ "item_code").as[String],
          "FSerialNo" -> None,
          "FTaxAmount" -> None,
          "FTaxRate" -> None
        )
      )
      val para =
        s"""{
           |"Creator": null,
           |"Model": {
           |    "FAddress": "广东省广州市天河区",
           |    "FConsignee": "五羊公司",
           |    "FCustNumber": null,
           |    "FDate": "$date",
           |    "FDeptNumber": null,
           |    "FEntity": [${para_fe.mkString(",")}],
           |    "FGYBillId": "$code_id",
           |    "FGYBillNo": "$code",
           |    "FInvoiceAmount": null,
           |    "FInvoiceContent": null,
           |    "FInvoiceNumber": null,
           |    "FInvoiceTitle": null,
           |    "FInvoiceType": null,
           |    "FMemo": "",
           |    "FOrderNo": null,
           |    "FOwnerNumber": null,
           |    "FOwnerTypeId": null,
           |    "FSalerNumber": null,
           |    "FShopNumber": "${shop_code}",
           |    "FStockNumber": "${wh_code}",
           |    "FTaxRegisterCode": null
           |  },
           |"NeedReturnFields": null,
           |"NeedUpDateFields": null,
           |"SubSystemId": null,
           |"deleteEntry": null,
           |"verifyBaseDataField": null
           |}""".stripMargin
      val kdPara = Json.parse(s"[$para]")
      // 写入金蝶
      val kdres = kdPost.post(kdPost.kingdeePostApi("ReturnStockService"), Json.parse(s"[$para]"))
      logger.debug(s"kdPara = ${kdPara.toString()}")
    } catch {
      case exception: Exception => logger.debug("saveTradeReturns2Kd catch exception:\n", exception)
    }
  }

  private def getTradeReturnsAtDays(start_date: String, end_date: String, receive: Int = 1) = {
    val limit = 10
    var page = 1
    var total = 1
    val lst: mutable.ArrayBuffer[JsValue] = mutable.ArrayBuffer()

    while (page <= total) {
      val para_list = Json.obj(
        "method" -> "gy.erp.trade.return.get",
        "page_no" -> page,
        "page_size" -> limit,
        "in_begin_time" -> start_date,
        "in_end_time" -> end_date,
        "receive" -> receive, // #入库状态 否 0:未入库 1:已入库
        "cancel" -> 0
      )
      val res = Await.result(gyPost.post(para_list), Duration.Inf)
      logger.debug(s"getTradeReturns -> res: ${res.toString()}")
      try {
        if ((res \ "success").as[Boolean]) {
          val a = (res \ "total").as[Int] / limit + 1
          if (a > total) total = a
          val arr = (res \ "tradeReturns").as[Array[JsValue]]
          for (f <- arr) {
            lst.append(f)
            this.saveTradeReturns2Kd(f)
          }
        } else {
          logger.debug(res.toString())
          page = total + 1
        }
        logger.debug(s"total=$total,page=$page")
        page += 1
        Thread.sleep(1000)
      } catch {
        case exception: Exception => logger.debug("getTradeReturns res->json", exception)
      }
    }
    lst.map(r => this.save2OSR(r))
    lst.toString()
  }

  def getDeliveryFromGy(p: OutStockPostParameters) = {
    logger.debug(p.toString)
    var result = new ListBuffer[String]
    if (p.status == 9) {
      val startDate = LocalDateTime.now().plusHours(-1)
      val endDate = LocalDateTime.now()
      result += getDeliveryAtDays(start_date = startDate.format(dateFormat), endDate.format(dateFormat))
    } else {
      var startDate, endDate = LocalDate.now()
      try {
        startDate = LocalDate.parse(p.sdate.substring(0, 10)) //.atZone(ZoneId.systemDefault()).toInstant
        endDate = LocalDate.parse(p.sdate.substring(13)) //.atZone(ZoneId.systemDefault()).toInstant
      } catch {
        case e: Exception => logger.debug(s"getDeliveryFromGy => sdate输入错误:", e);
      }
      logger.info("getDeliveryFromGy" + startDate + " ~ " + endDate)
      var dateEnd = startDate
      while (dateEnd.compareTo(endDate) <= 0) {
        logger.info(dateEnd.toString)
        val startDate = LocalDateTime.parse(dateEnd.toString + "T00:00:00")
        val endDate = LocalDateTime.parse(dateEnd.toString + "T00:00:00").plusDays(1)
        val history = if (startDate.compareTo(LocalDateTime.now().plusDays(-7)) <= 0) true else false
        result += getDeliveryAtDays(start_date = startDate.format(dateFormat), end_date = endDate.format(dateFormat), history = history)
        dateEnd = dateEnd.plusDays(1)
      }
    }
    result
  }

  def getTradeReturnsFromGy(p: OutStockPostParameters) = {
    logger.debug(p.toString)
    var result = new ListBuffer[String]
    if (p.status == 9) {
      val startDate = LocalDateTime.now().plusHours(-1)
      val endDate = LocalDateTime.now()
      result += getTradeReturnsAtDays(start_date = startDate.format(dateFormat), end_date = endDate.format(dateFormat))
    } else {
      var startDate, endDate = LocalDate.now()
      try {
        startDate = LocalDate.parse(p.sdate.substring(0, 10)) //.atZone(ZoneId.systemDefault()).toInstant
        endDate = LocalDate.parse(p.sdate.substring(13)) //.atZone(ZoneId.systemDefault()).toInstant
      } catch {
        case e: Exception => logger.debug(s"getTradeReturnsAtDays => sdate输入错误:", e);
      }
      logger.info("getTradeReturnsAtDays" + startDate + " ~ " + endDate)
      var dateEnd = startDate
      while (dateEnd.compareTo(endDate) <= 0) {
        logger.info(dateEnd.toString)
        val startDate = LocalDateTime.parse(dateEnd.toString + "T00:00:00")
        val endDate = LocalDateTime.parse(dateEnd.toString + "T00:00:00").plusDays(1)
        result += getTradeReturnsAtDays(start_date = startDate.format(dateFormat), end_date = endDate.format(dateFormat))
        dateEnd = dateEnd.plusDays(1)
      }
    }
    result
  }

  def getDataFromGy(p: OutStockPostParameters) = {
    logger.debug(p.toString)
    p.p2 match {
      case "delivery" => "delivery"
      case "tradereturn" => "tradereturn"
    }
  }


}
